from scan import getToken


class newNode:
    def __init__(self, kind, nodeKind) -> None:
        self.sibling = None  # 兄弟
        self.child = [None, None, None]  # 最多3个孩子
        self.lineno = None  # 在转换的以后步骤中出现错误时能够打印源代码行数

        self.kind = kind  # statement or exp
        self.nodeKind = nodeKind  # 语句或表达式的种类，更细

        self.attr = None  # TokenType op;int val;char * name;
        self.type = None  # for type checking of exps

    def __repr__(self) -> str:
        return self.nodeKind

# typedef enum {StmtK,ExpK} NodeKind;
# typedef enum {IfK,RepeatK,AssignK,ReadK,WriteK} StmtKind;
# typedef enum {OpK,ConstK,IdK} ExpKind;

token=''
tokenString= ''

# stmt-sequence -> stmt-sequence ; statement | statement 改写为
# stmt-sequence -> statement { ; statement }
def stmt_sequence() -> newNode(str, str):
    t = statement()
    p = t

    #alist = ['endfile','end','else','until'] #只有这些token不会出现在语句的开头
    while token == 'semi':
        match('semi')
        q = statement()
        if q:
            if t==None:t =p =q
            else:
                p.sibling = q
                p=q
    return t

# statement -> if-stmt | repeat-stmt | assign-stmt | read-stmt | write-stmt
def statement() -> newNode(str, str):
    t = None
    if token == 'if': t = if_stmt()
    elif token == 'repeat': t = repeat_stmt()
    elif token == 'id': t = assign_stmt()
    elif token == 'read': t = read_stmt()
    elif token == 'write': t = write_stmt()
    else:
        exit('wrong in statement')
    return t


def match(expected):
    global token, tokenString
    if expected == token:
        token, tokenString = getToken()
    else:
        print('unexpected token -> ')

# if-stmt -> if exp then stmt-sequence end
#           |if exp then stmt-sequence else stmt-sequence end
def if_stmt():
    t = newNode('stmt', 'if')
    match('if')
    t.child[0] = exp()
    match('then')
    t.child[1] = stmt_sequence()
    if token == 'else':
        match('else')
        t.child[2] = stmt_sequence()
    match('end')
    return t

# repeat-stmt -> repeat stmt-sequence until exp
def repeat_stmt():
    t = newNode('stmt', 'repeat')
    match('repeat')
    t.child[0] = stmt_sequence()
    match('until')
    t.child[1] = exp()
    return t

# assign-stmt -> identifier := exp
def assign_stmt():
    t = newNode('stmt', 'assign')
    t.attr = tokenString
    match('id')
    match('assign')
    t.child[0] = exp()
    return t

# read_stmt -> read identifier
def read_stmt():
    t = newNode('stmt', 'read')
    match('read')
    if token == 'id':
        t.attr = tokenString
    match('id')
    return t

# write-stmt -> write exp
def write_stmt():
    t = newNode('stmt', 'write')
    match('write')
    t.child[0] = exp()
    return t


# exp -> simple-exp comparison-op simple-exp | simple-exp
def exp():
    t = simple_exp()
    if token in ['cmplt','cmpeq']:
        p = newNode('exp', 'op')
        p.child[0] = t
        p.attr = token
        t = p
        match(token)
        t.child[1] = simple_exp()
    return t

# simple-exp -> simple-exp addop term | term
# simple-exp -> term { addop term }
def simple_exp():
    t = term()
    while token in ['add','sub']:
        p = newNode('exp', 'op')
        p.child[0] = t
        p.attr = token
        t = p
        match(token)
        t.child[1] = term()
    return t

# term -> term mulop factor | factor 左递归
# 等价于
# term -> factor { mulop factor } 拓展巴克斯范式
# 先匹配一个factor，再循环匹配 mulop factor
def term():
    t = factor()
    while token in ['mul','over']:
        p = newNode('exp', 'op')
        p.child[0]=t
        p.attr = token
        t = p

        match(token)
        p.child[1] = factor()
    return t

# factor -> (exp) | number | identifier
def factor():
    if token == 'num':
        t=newNode('exp', 'num')
        t.attr = tokenString
        match('num')
    elif token == 'id':
        t=newNode('exp', 'id')
        t.attr = tokenString
        match('id')
    elif token == 'lparen':
        match('lparen')
        t = exp()
        match('rparen')
    else:
        print("a wrong happen")

    return t


def runParse():
    match('')
    parseTree = stmt_sequence()
    return parseTree


if __name__ == '__main__':
    runParse()
